#include "radar.h"
#include <chrono>
#include <plog/Log.h>
#include <sys/time.h>
#include <thread>

extern "C" {
#include "fpga_interface.h"
#include "microwave_module.h"
#include "sense_node.h"
#include "target_node.h"
#include "timing_module.h"
}

// 带宽的可选项有: 5k, 25k, 60k, 200k, 1.28m, 6.4m
const uint32_t bandwidth_code_tab[] = {6400, 5, 25, 60, 200, 1280, 6400};
constexpr uint16_t bandwidth_code_tab_len = sizeof(bandwidth_code_tab) / sizeof(uint32_t);

static uint32_t get_bandwidth_code(uint32_t bandwidth) {
    uint16_t i;
    for (i = 1; i < bandwidth_code_tab_len; i++) {
        if (bandwidth_code_tab[i] >= bandwidth) {
            break;
        }
    }
    if (i >= bandwidth_code_tab_len)
        i = 0;
    return i;
}

static uint32_t convert_freq(uint16_t in) {
    uint32_t freq;
    if (in < 0x1FFFF) {
        freq = 204800 - in * 204800 / 16384;
    } else {
        freq = in * 204800 / 16384;
    }
    return freq;
}

Radar::Radar(char *signalefilepath) : signal_file_path(signalefilepath) {
    microwave_module_init();
    fpga_init(0);
    timing_module_init();
}

Radar::~Radar() {
    close_fpga(0);
    close_microwave_module();
    close_timing_module();
}

std::list<signaltable_t> *Radar::returnSignalUnderDetection() { return &m_signal_under_detection; }

std::list<signaltable_t> *Radar::returnSignalFound() { return &m_signal_found; }

std::mutex *Radar::returnMutex() {
    // 在通讯线程使用，对信号表上锁
    return &m_mutex;
}

void Radar::clearSignalUnderDetection() {
    std::lock_guard<std::mutex> lck(m_mutex);
    for (auto &signal : m_signal_under_detection) {
        delete[] signal.IQ_table;
    }
    m_signal_under_detection.clear();
}

void Radar::addSignalUnderDetection(uint16_t id, uint32_t frequency, uint16_t bandwidth, int16_t attenuation) {
    // 如果待检测的频率和带宽在要求范围内，则添加至待检测信号表
    if (frequency > 0 && bandwidth > 0) {
        std::lock_guard<std::mutex> lck(m_mutex);
        signaltable_t new_signal = {.id = id,
                                    .frequency = frequency,
                                    .bandwidth = bandwidth,
                                    .IQ_size = 0,
                                    .IQ_table = nullptr};
        m_signal_under_detection.push_back(new_signal);

        // 按照检测信号表的窄带参数设置DDC
        if (!m_signal_under_detection.empty()) {
            auto &signal = m_signal_under_detection.front();
            set_microwave_rx_frequency(static_cast<uint32_t>(signal.frequency), attenuation);
            notifyTimeSync();
        }
    }
}

void Radar::set_sense_config_parameters(sense_config_para_t *parameters) {
    if (parameters)
        m_payload_parameters = *parameters;
}

void Radar::emit_signal(target_signal_def *parameters) {
    set_microwave_tx_frequency(parameters->frequency, parameters->power);
    set_self_generated_signal(parameters->type, parameters->modulation, parameters->frameStructure,
                              parameters->frameDelay, get_bandwidth_code(parameters->bandwidth));
}

void Radar::senseTask() {
    uint16_t *fft_ram;
    while (1) {
        std::unique_lock<std::mutex> lck(m_mutex);
        m_sense_cond.wait(lck, [this] { return sense_ready; });

        // 参数合法性检查
        if (m_payload_parameters.minFrequency < 800000 ||
            m_payload_parameters.maxFrequency > 2000000 ||
            m_payload_parameters.maxFrequency < m_payload_parameters.minFrequency ||
            m_payload_parameters.maxBandwidth == 0 || m_payload_parameters.minBandwidth == 0) {
            PLOG_DEBUG << "感知载荷参数错误！";
            sense_ready = false;
            lck.unlock();
            continue;
        }
        auto start = std::chrono::system_clock::now();

        // 只有在全频段扫描和指定频段扫描时才需要FFT
        // 窄带扫描和盲采无需执行以下步骤
        if (m_payload_parameters.mode == 2 || m_payload_parameters.mode == 3) {
            sense_ready = false;
            lck.unlock();
            notifyNarrowBandScan();
            continue;
        }

        // 全频段扫描，800MHz ~ 2000MHz
        if (m_payload_parameters.mode == 0) {
            m_payload_parameters.minFrequency = 800000;
            m_payload_parameters.maxFrequency = 2000000;
        }

        PLOG_DEBUG << "开启一次FFT";
        m_signal_found.clear();

        uint32_t freq = m_payload_parameters.minFrequency;
        // 一次扫描带宽是60000kHz，为提高效率，从最小频率+30000kHz开始扫
        if (freq < m_payload_parameters.maxFrequency - 30000) {
            freq += 30000;
        }
        for (; freq <= m_payload_parameters.maxFrequency; freq += 60000) {
            PLOG_DEBUG << "当前检测频率：" << freq / 1000 << " MHz";
            set_microwave_rx_frequency(freq, m_payload_parameters.attenuation);
            std::this_thread::sleep_for(std::chrono::microseconds(50));
            start_FFT_once(260000);
            uint32_t timeout = 10000;
            while (timeout > 0 && get_FFT_state() != 1) {
                timeout--;
            }
            if (timeout == 0) {
                PLOG_DEBUG << "FFT Timeout!";
            }

            uint16_t signal_num = read_signal_number();
            struct signal_in_fft_t *fft_ram = read_signal_val(signal_num);

            time_t rawtime;
            uint64_t timestamp;

            time(&rawtime);
            timestamp = (uint64_t)rawtime;

            for (int i = 0; i < signal_num; i++) {
                uint32_t amplitude = fft_ram[i].amplitude;
                uint32_t detect_freq = convert_freq(fft_ram[i].freq_raw);
                uint16_t bandwidth;
                if (fft_ram[i].high_freq_raw > 0) {
                    uint32_t detect_high_freq = convert_freq(fft_ram[i].high_freq_raw);
                    if (detect_high_freq > detect_freq)
                        bandwidth = (detect_high_freq - detect_freq) * 2;
                    else
                        bandwidth = (detect_freq - detect_high_freq) * 2;
                } else {
                    bandwidth = 0;
                }

                if (detect_freq > 123300 && detect_freq < 183900) {
                    detect_freq = freq + detect_freq - 153600;
                    signaltable_t new_signal = {.id = static_cast<uint16_t>(i),
                                                .arrivetime = timestamp,
                                                .endtime = timestamp,
                                                .frequency = detect_freq,
                                                .bandwidth = bandwidth,
                                                .longitude = i,
                                                .latitude = i,
                                                .height = i,
                                                .speed = static_cast<float>(i),
                                                .angle = static_cast<float>(i)};
                    m_signal_found.push_back(new_signal);
                }
            }
        }
        auto end = std::chrono::system_clock::now();
        PLOG_DEBUG << "发现信号数量：" << m_signal_found.size();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
        PLOG_DEBUG << "花费了"
                   << double(duration.count()) * std::chrono::microseconds::period::num /
                          std::chrono::microseconds::period::den
                   << "秒";

        sense_ready = false;
        lck.unlock();
        send_signal_table_func();
    }
}

/**
 * @brief 窄带扫描
 *
 */
void Radar::narrowBandScanTask() {
    while (1) {
        {
            std::unique_lock<std::mutex> lck(m_mutex);
            m_narrow_band_scan_cond.wait(lck, [this] { return narrow_band_scan_ready; });
            PLOG_DEBUG << "开启一轮窄带扫描";
        }

        while (narrow_band_scan_ready) {
            // 对检测信号表的第一个频点窄带进行数字下变频
            if (!m_signal_under_detection.empty()) {
                auto &signal = m_signal_under_detection.front();

                uint16_t i = get_bandwidth_code(signal.bandwidth);
                // 根据采样总数，带宽计算出存储时长

                uint64_t store_time =
                    (uint64_t)IQ_GROUP_COUNT * 1000000000 / 200 / bandwidth_code_tab[i] / 1000;
                printf("存储时长: %lld * 200ns\n", store_time);

                set_microwave_rx_frequency(static_cast<uint32_t>(signal.frequency), m_payload_parameters.attenuation);
                start_DDC(153600, i, 0);
                store_DDC_result(store_time, IQ_GROUP_COUNT * sizeof(IQstruct_t) / 32, 0);
                if (wait_DDC() == -1) {
                    printf("DDC Timeout!\n");
                }
                stop_DDC(0);

                if (signal.IQ_table == nullptr) {
                    // 每组有I，Q两个数据
                    signal.IQ_table = new IQstruct_t[IQ_GROUP_COUNT];
                }
                signal.IQ_size = IQ_GROUP_COUNT * sizeof(IQstruct_t);

                uint32_t bytes_to_read = signal.IQ_size;
                uint32_t bytes_already_read = 0;
                while (bytes_to_read > 0) {
                    if (bytes_to_read >= 0x100000) {
                        read_fpga_ddr(bytes_already_read / 32, 0x100000 / 32,
                                      (uint8_t *)signal.IQ_table + bytes_already_read, 0);
                        bytes_to_read -= 0x100000;
                        bytes_already_read += 0x100000;
                    } else {
                        read_fpga_ddr(bytes_already_read / 32, bytes_to_read / 32,
                                      (uint8_t *)signal.IQ_table + bytes_already_read, 0);
                        bytes_to_read = 0;
                    }
                }
                printf("count: %d\n", (spi_read_fpga(1, 0x41) << 16) | spi_read_fpga(1, 0x40));
                spi_write_fpga(1, 0x40, 0);
                spi_write_fpga(1, 0x41, 0);

                uint8_t day, hour, min, sec;
                uint32_t ns2048;
                char signal_file_name[50];
                read_start_time_ch1(&day, &hour, &min, &sec, &ns2048);
                printf("%d 日 %d 时 %d 分 %d 秒\n", day, hour, min, sec);
                printf("%u / 204800000 秒\n", ns2048);

                struct precise_time_type {
                    uint8_t day;
                    uint8_t hour;
                    uint8_t min;
                    uint8_t sec;
                    uint32_t ns2048;
                } *precise_time;

                precise_time = (struct precise_time_type *)&signal.arrivetime;
                precise_time->day = day;
                precise_time->hour = hour;
                precise_time->min = min;
                precise_time->sec = sec;
                precise_time->ns2048 = ns2048;

                read_end_time_ch1(&day, &hour, &min, &sec, &ns2048);
                precise_time = (struct precise_time_type *)&signal.endtime;
                precise_time->day = day;
                precise_time->hour = hour;
                precise_time->min = min;
                precise_time->sec = sec;
                precise_time->ns2048 = ns2048;

                // 保存IQ数据到硬盘
                if (IQ_store_enable) {
                    snprintf(signal_file_name, sizeof(signal_file_name),
                             "%s%dM_%dK_%02d_%02d_%02d_%d", signal_file_path,
                             signal.frequency / 1000, signal.bandwidth, hour, min, sec, ns2048);

                    fout.open(signal_file_name, std::ios::out | std::ios::trunc);
                    if (fout.is_open() == false) {
                        PLOG_INFO << "打开文件失败";
                    } else {
                        fout << "frequency: " << signal.frequency
                             << " bandwidth: " << signal.bandwidth
                             << " time: " << static_cast<int>(hour) << ":" << static_cast<int>(min)
                             << ":" << static_cast<int>(sec) << "  " << ns2048 << std::endl;
                        for (int i = 0; i < IQ_GROUP_COUNT; i++) {
                            fout << signal.IQ_table[i].IQI << "," << signal.IQ_table[i].IQQ
                                 << std::endl;
                        }
                        fout.close();
                    }
                }

                if (task_IQ_TX_is_running) {
                    send_IQ_func(&signal);
                }
            }
            narrow_band_scan_ready = false;
        }
        narrow_band_scan_ready = false;
    }
}

void Radar::timeSyncTask() {
    while (true) {
        std::unique_lock<std::mutex> lk(m_time_sync_mutex);
        // m_time_sync_cond.wait_for(lk, std::chrono::seconds(10),
        //                           [this] { return trigger_time_sync; });
        m_time_sync_cond.wait(lk, [this] { return trigger_time_sync; });
        struct timeval the_tv;
        struct tm the_tm;

        the_tm = time_sync();
        while (the_tm.tm_year < (2024 - 1990)) {
            the_tm = time_sync();
        }

        auto start = std::chrono::system_clock::now();
        // 设置 FPGA 时间
        set_timestamp(the_tm.tm_min, the_tm.tm_sec, the_tm.tm_mday, the_tm.tm_hour);

        int sec = the_tm.tm_sec;
        auto end = std::chrono::system_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

        // 监测秒变化，同时避免超时，等待时间不超过1.1秒
        while (the_tm.tm_sec == sec && duration < std::chrono::microseconds(1100000)) {
            the_tm = time_sync();
        }

        // 重复两次写入，因为FPGA逻辑判断秒数不同才刷新时间
        set_timestamp(the_tm.tm_min, the_tm.tm_sec, the_tm.tm_mday, the_tm.tm_hour);

        time_t tt = mktime(&the_tm);
        tt += 8 * 60 * 60; // 换算到北京时间
        the_tv.tv_sec = tt;
        settimeofday(&the_tv, NULL);
        trigger_time_sync = false;
    }
}

// 开始一次时间同步
void Radar::notifyTimeSync() {
    std::unique_lock<std::mutex> lk(m_time_sync_mutex, std::defer_lock);
    if (lk.try_lock()) {
        trigger_time_sync = true;
        m_time_sync_cond.notify_one();
    }
}

void Radar::notifySense() {
    std::lock_guard<std::mutex> lck(m_mutex);
    sense_ready = true;
    m_sense_cond.notify_one();
}

void Radar::notifyNarrowBandScan() {
    std::lock_guard<std::mutex> lck(m_mutex);
    narrow_band_scan_ready = true;
    m_narrow_band_scan_cond.notify_one();
}

void Radar::stopNarrowBandScan() {
    std::lock_guard<std::mutex> lck(m_mutex);
    narrow_band_scan_ready = false;
}

void Radar::startIQ_TX_Task() { IQ_store_enable = true; }

void Radar::stopIQ_TX_Task() { IQ_store_enable = false; }
